home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / pwdutils.00 / pwdutils / pwdutils-1.00 / vipw.c < prev    next >
C/C++ Source or Header  |  1996-05-08  |  4KB  |  187 lines

  1. /*
  2. ** Copyright 1996 Thorsten Kukuk <kukuk@uni-paderborn.de>
  3. **
  4. ** This program is free software; you can redistribute it and/or modify
  5. ** it under the terms of the GNU General Public License as published by
  6. ** the Free Software Foundation; either version 2 of the License, or
  7. ** (at your option) any later version.
  8. **
  9. ** This program is distributed in the hope that it will be useful,
  10. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ** GNU General Public License for more details.
  13. **
  14. ** You should have received a copy of the GNU General Public License
  15. ** along with this program; if not, write to the Free Software
  16. ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. #include <pwd.h>
  20. #include <errno.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <signal.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <fcntl.h>
  29. #include <waitflags.h>
  30. #include <sys/wait.h>
  31. #include <getopt.h>
  32.  
  33. #include "pwdutils.h"
  34.  
  35. #include "version.h"
  36.  
  37. static struct option vipw_options[] = {
  38.   { "version",      no_argument,       0, 'v' },
  39.   { NULL,           no_argument,       0, '0' },
  40. };
  41.  
  42. static char *vipw_str = "v";
  43.  
  44.  
  45. void pwd_exit(int code)
  46. {
  47.   unlink(PWD_TEMP);
  48.   ulckpwdf();
  49.   exit(code);
  50. }
  51. void create_tmpfile()
  52. {
  53.   int nr, nw, off, from, to;
  54.   char buf[8*1024];
  55.         
  56.   from = open(PWD_PATH, O_RDONLY, 0);
  57.   if (from < 0) 
  58.     {
  59.       fprintf(stderr, "vipw: %s: %s\n", PWD_PATH, strerror(errno));
  60.        pwd_exit(1);
  61.     }
  62.   
  63.   if ((to = open(PWD_TEMP, O_WRONLY|O_CREAT, 0644)) == -1) 
  64.     {
  65.       fprintf(stderr,"vipw: %s: %s\n", PWD_TEMP, strerror(errno));
  66.       pwd_exit(1);
  67.     }
  68.  
  69.   while ((nr = read(from, buf, sizeof(buf))) > 0)
  70.     for (off = 0; off < nr; nr -= nw, off += nw)
  71.       if ((nw = write(to, buf + off, nr)) < 0)
  72.         pwd_error("Error by copying " PWD_PATH " to " PWD_TEMP, PWD_PATH);
  73.   if (nr < 0)
  74.     pwd_error("Error by copying " PWD_PATH " to " PWD_TEMP, PWD_PATH);
  75. }
  76.  
  77. void call_editor()
  78. {
  79.   static char *editor, *prgname, *arg;
  80.   int pid, sock;
  81.  
  82.   if ((editor = getenv("EDITOR"))==NULL)
  83.     editor = VI_PATH;
  84.  
  85.   if ((prgname = strrchr(strtok(editor," \t"), '/')) != NULL)
  86.     prgname++;
  87.   else 
  88.     prgname = editor;
  89.   
  90.   /* I need the parameter in the EDITOR environment variable.
  91.   ** This isn't a security risc, since only root is allowed
  92.   ** to run this program and edit the passwd file.
  93.   ** VIPW SHOULD NEVER RUN SETUID ROOT !
  94.   */
  95.   arg = strtok(NULL,"\n");
  96.  
  97.   switch(pid=fork())
  98.     {
  99.     case -1:
  100.       perror("Cannot fork");
  101.       exit(-1);
  102.       break;
  103.     case 0:
  104.       if(arg == NULL)
  105.     execlp(editor, prgname, PWD_TEMP, NULL);
  106.       else
  107.     execlp(editor, prgname, arg, PWD_TEMP, NULL);
  108.       _exit(1);
  109.       break;
  110.     default:
  111.       while(1)
  112.     {
  113.       pid = waitpid(pid,&sock, WUNTRACED);
  114.       if(WIFSTOPPED(sock))
  115.         {
  116.           kill(getpid(),SIGSTOP);
  117.           kill(pid, SIGCONT);
  118.         }
  119.       else
  120.         break;
  121.     }
  122.       break;
  123.     }
  124. }
  125.  
  126. int main(int argc, char *argv[])
  127. {
  128.   struct stat begin, end;
  129.   int c, index = 0;
  130.   
  131.   while((c = getopt_long(argc, argv, vipw_str, vipw_options, &index))!= EOF)
  132.     {
  133.       switch(c)
  134.         {
  135.         case 'v':
  136.           printf("pwdutils %s\n", version);
  137.           exit (0);
  138.           break;
  139.         default:
  140.           break;
  141.         }
  142.     }
  143.  
  144.   argc-=optind;
  145.   argv+=optind;
  146.  
  147.   if(getuid() != 0)
  148.     {
  149.       fprintf(stderr,"vipw: Only root could edit %s !\n", PWD_PATH);
  150.       exit(1);
  151.     }
  152.  
  153.   pwd_init();
  154.   if(lckpwdf() != 0)
  155.     {
  156.       fprintf(stderr,"vipw: Can't lock /etc/passwd! Try again later.\n");
  157.       exit(1);
  158.     }
  159.   
  160.   create_tmpfile();
  161.     
  162.   if (stat(PWD_TEMP, &begin))
  163.     pwd_error(strerror(errno), PWD_PATH);
  164.  
  165.   call_editor();
  166.  
  167.   if (stat(PWD_TEMP, &end))
  168.     pwd_error(strerror(errno), PWD_PATH);
  169.   if (begin.st_mtime == end.st_mtime) 
  170.     {
  171.       fprintf(stderr, "vipw: no changes made, %s unchanged\n",PWD_PATH);
  172.     }
  173.   else
  174.     {
  175.       unlink(PWD_PATH);
  176.       if (rename(PWD_TEMP, PWD_PATH) == -1) 
  177.         {
  178.           fprintf(stderr, "vipw: can't unlock %s: %s (your changes are still in %s)\n", 
  179.                   PWD_PATH, strerror(errno), PWD_TEMP);
  180.       exit(1);
  181.     }
  182.       unlink(PWD_TEMP);
  183.       
  184.     }
  185.   pwd_exit(0);
  186. }
  187.